using System;
using System.Collections.Generic;
using System.Text;
using SlimDX;

namespace miciv
{
    public class LayoutProcessor
    {
        public const int ChildrenCount = -1;

        protected Frame m_targetFrame;
        protected int m_sRows;
        protected int m_sColumns;
        protected int m_sActualRows;
        protected int m_sActualColumns;
        protected int m_sTargetChildrenCount;
        protected bool m_bFeedRowFirst;
        protected bool m_bNeedUpdate;

        public LayoutProcessor(Frame _targetFrame)
        {
            this.m_targetFrame = _targetFrame;
            this.m_sRows = 0;
            this.m_sColumns = 0;
            this.m_sActualRows = 0;
            this.m_sActualColumns = 0;
            this.m_sTargetChildrenCount = 0;
            this.m_bFeedRowFirst = false;
            this.m_bNeedUpdate = false;
        }

        virtual public int Rows
        {
            get
            {
                return this.m_sRows;
            }
            set
            {
                if (this.m_sRows != value)
                {
                    this.m_sRows = value;
                    this.m_sActualRows = value;
                    this.m_bNeedUpdate = true;
                }
            }
        }

        virtual public int Columns
        {
            get
            {
                return this.m_sColumns;
            }
            set
            {
                if (this.m_sColumns != value)
                {
                    this.m_sColumns = value;
                    this.m_sActualColumns = value;
                    this.m_bNeedUpdate = true;
                }
            }
        }

        virtual public bool FeedRowFirst
        {
            get
            {
                return this.m_bFeedRowFirst;
            }
            set
            {
                if (value != this.m_bFeedRowFirst)
                {
                    this.m_bFeedRowFirst = value;
                    this.m_bNeedUpdate = true;
                }
            }
        }

        virtual public bool NeedUpdate
        {
            get
            {
                return ((false != this.m_bNeedUpdate) || (this.m_sTargetChildrenCount != this.m_targetFrame.Children.Count));
            }
        }

        public void Update()
        {
            if (false != this.NeedUpdate)
            {
                this.m_sTargetChildrenCount = this.m_targetFrame.Children.Count;
                this.m_bNeedUpdate = false;

                if (LayoutProcessor.ChildrenCount == this.m_sColumns)
                {
                    this.m_sActualColumns = this.m_sTargetChildrenCount;
                }
                if (LayoutProcessor.ChildrenCount == this.m_sRows)
                {
                    this.m_sActualRows = this.m_sTargetChildrenCount;
                }

                if (false != this.m_targetFrame.AutoResize)
                {
                    // if target frame has enabled auto resize then we precompute its final size based on its children size.
                    this.ComputeSizeAndPosition(true);
                }
                // compute target frame children position based on its size.
                this.ComputeSizeAndPosition(false);
            }
        }

        protected void ComputeSizeAndPosition(bool _bPreComputation)
        {
            float xx = 0.0f;
            float yy = 0.0f;
            float targetChildWidthMax = 0.0f;
            float targetChildHeightMax = 0.0f;
            float targetFrameWidth = 0.0f;
            float targetFrameHeight = 0.0f;
            int row = 0;
            int column = 0;

            if (false != this.m_bFeedRowFirst)
            {
                xx -= this.m_targetFrame.Size.X / 2.0f;
                foreach (Frame targetChild in this.m_targetFrame.Children)
                {
                    if (false != targetChild.NeedLayoutUpdate)
                    {
                        targetChild.UpdateLayout();
                    }
                    if (false == _bPreComputation)
                    {
                        xx += targetChild.Size.X / 2.0f;
                        targetChild.Position = new Vector2(xx, yy);
                    }

                    if (targetChildWidthMax < targetChild.Size.X)
                    {
                        targetChildWidthMax = targetChild.Size.X;
                    }
                    if (targetChildHeightMax < targetChild.Size.Y)
                    {
                        targetChildHeightMax = targetChild.Size.Y;
                    }

                    targetFrameWidth += targetChild.Size.X;
                    xx += targetChild.Size.X / 2.0f;
                    ++column;

                    if (this.m_sActualColumns == column)
                    {
                        xx = 0.0f;
                        yy -= targetChildHeightMax;
                        targetFrameHeight += targetChildHeightMax;
                        ++row;
                    }
                }
            }
            else
            {
                yy += this.m_targetFrame.Size.Y / 2.0f;
                foreach (Frame targetChild in this.m_targetFrame.Children)
                {
                    if (false != targetChild.NeedLayoutUpdate)
                    {
                        targetChild.UpdateLayout();
                    }
                    if (false == _bPreComputation)
                    {
                        yy -= targetChild.Size.Y / 2.0f;
                        targetChild.Position = new Vector2(xx, yy);
                    }

                    if (targetChildWidthMax < targetChild.Size.X)
                    {
                        targetChildWidthMax = targetChild.Size.X;
                    }
                    if (targetChildHeightMax < targetChild.Size.Y)
                    {
                        targetChildHeightMax = targetChild.Size.Y;
                    }

                    targetFrameHeight += targetChild.Size.Y;
                    yy -= targetChild.Size.Y / 2.0f;
                    ++row;

                    if (this.m_sActualRows == row)
                    {
                        yy = 0.0f;
                        xx += targetChildWidthMax;
                        targetFrameWidth += targetChildWidthMax;
                        ++column;
                    }
                }
            }

            if ((false != _bPreComputation) && (false != this.m_targetFrame.AutoResize))
            {
                this.m_targetFrame.Size = new Vector2(targetFrameWidth, targetFrameHeight);
            }
        }
    }
}
